/*
 * Node.cpp
 *
 *  Created on: Dec 4, 2009
 *      Author: abhishek
 */

/*
 * Node.h
 *
 *  Created on: Dec 4, 2009
 *      Author: abhishek
 */

#include "Node.h"

Node::Node() {
	minPriceChange_ = -0.07;
	maxPriceChange_ = 0.07;
	//	maxPriceChange_ = 0.00 ;
}

Node::~Node() {
}

int Node::nodeId() {
	return nodeId_;
}

void Node::nodeIdIs(int nodeId) {
	nodeId_ = nodeId;
}

int Node::degree() {
	return degree_;
}

map<int, double> Node::guv() {
	return guv_;

}

set<int>
Node::neighbours(){

	set<int> neighbrs ;
	map<int, double>::iterator it;
	for (it = guv_.begin(); it != guv_.end(); ++it)
		neighbrs.insert(it->first);

	return neighbrs;
}

void
Node::printNeighbours(){

	map<int, double>::iterator it;
	for (it = guv_.begin(); it != guv_.end(); ++it)
		cout << it->first << ":" ;
	cout << endl ;
}

void Node::guvAdd(int nodeId, double gValue) {
	guv_[nodeId] = gValue;
	degree_ = guv_.size();
}

double Node::guvg(int nodeId) {
	return guv_[nodeId];
}

double Node::revenueGOfNeighbours(Node** nodeIdToNodePtrIndex) {

	double neighbourRevenue = 0.000;
	map<int, double>::iterator it;
	for (it = guv_.begin(); it != guv_.end(); ++it){
		Node* n = nodeIdToNodePtrIndex[it->first];
		neighbourRevenue = neighbourRevenue + (n->guvg(nodeId_)) * n->price();
	}

	return neighbourRevenue;
}

double Node::revenueGOfNeighboursExceptV(Node** nodeIdToNodePtrIndex, int nodeid) {

	double neighbourRevenue = 0.000;
	map<int, double>::iterator it;
	for (it = guv_.begin(); it != guv_.end(); ++it){
		if (nodeid == it->first)
			continue ;
		Node* n = nodeIdToNodePtrIndex[it->first];
		neighbourRevenue = neighbourRevenue + (n->guvg(nodeId_)) * n->price();
	}

	return neighbourRevenue;
}


double
Node::gRevenue(){
	double nodeRevenue = 0.00;
	map<int, double>::iterator it;
	for (it = guv_.begin(); it != guv_.end(); ++it)
		nodeRevenue += it->second;

	nodeRevenue = nodeRevenue * (price_);
	return nodeRevenue;
}

double Node::revenueNeighboursuv(Node* n2, Node** nodeIdToNodePtrIndex) {

	map<int, double>::iterator it;
	set<int> nodeIds;
	for (it = guv_.begin(); it != guv_.end(); ++it) {
		if (it->first != n2->nodeId()) {
			nodeIds.insert(it->first);
		}
	}

	map<int, double> n2guv = n2->guv();
	for (it = n2guv.begin(); it != n2guv.end(); ++it) {
		if (it->first != nodeId_) {
			nodeIds.insert(it->first);
		}
	}

	double neighbourRevenue = 0.000 ;
	set<int>::iterator setIterator;
	for ( setIterator=nodeIds.begin() ; setIterator != nodeIds.end(); setIterator++ ){
		Node* n = nodeIdToNodePtrIndex[*setIterator];
		neighbourRevenue = neighbourRevenue + (n->guvg(nodeId_)) * n->price();

	}
	return neighbourRevenue ;

}

double Node::f() {
	return f_;
}

void Node::fIs(double f) {
	f_ = f;
}

double Node::price() {
	return price_;
}

void Node::priceIs(double price) {
	price_ = price;
}

double Node::influence() {
	return influence_;
}

void Node::influenceIs(double influence) {
	influence_ = influence;
}

double Node::revenue() {

	double nodeRevenue = f_;
	map<int, double>::iterator it;
	for (it = guv_.begin(); it != guv_.end(); ++it)
		nodeRevenue += it->second;

	nodeRevenue = nodeRevenue * (price_);
	return nodeRevenue;
}

void Node::updateAtributes(double delta, Node** nodeIdToNodePtrIndex) {

	price_ = price_ * (1 + delta);
	f_ = f_ * (1 - delta);
	map<int, double>::iterator it;
	vector<int> nodeIds;
	for (it = guv_.begin(); it != guv_.end(); ++it)
		nodeIds.push_back(it->first);

	for (unsigned int i = 0; i < nodeIds.size(); i++) {
		guv_[nodeIds[i]] = guv_[nodeIds[i]] * (1 - influence_ * delta);

		Node* n = nodeIdToNodePtrIndex[nodeIds[i]];

		double check = n->guvg(nodeId_);
		n->guvAdd(nodeId_, guv_[nodeIds[i]]);
		if (check == n->guvg(nodeId_)) {
			cout << "ERROR: could not update neighbours g values " << endl;
		}
	}

}

void Node::updateAtributes(Node* n2, double bestDelta, double bestDelta2,
		Node** nodeIdToNodePtrIndex) {

	price_ = price_ * (1 + bestDelta);
	f_ = f_ * (1 - bestDelta);
	map<int, double>::iterator it;
	vector<int> nodeIds;
	for (it = guv_.begin(); it != guv_.end(); ++it) {
		if (it->first != n2->nodeId()) {
			nodeIds.push_back(it->first);
		}
	}

	//double iuiv = (influence_*bestDelta - n2->influence()*bestDelta2) ;

	// New way when u scale the stuff...
	double iuiv = (influence_ * bestDelta - n2->influence() * bestDelta2)
			/ 2.000;

	guv_[n2->nodeId()] = guv_[n2->nodeId()] * (1 - iuiv);

	for (unsigned int i = 0; i < nodeIds.size(); i++) {
		guv_[nodeIds[i]] = guv_[nodeIds[i]] * (1 - influence_ * bestDelta);

		Node* n = nodeIdToNodePtrIndex[nodeIds[i]];
		n->guvAdd(nodeId_, guv_[nodeIds[i]]);
	}

}

void Node::influentialNodeRevenue(double& bestDeltaPrice,
		double& maxDeltaRevenue, Node** nodeIdToNodePtrIndex) {

	double deltaPrice = minPriceChange_;
	double doublePrice = ((double) price_);

	double pf = doublePrice * f_;
	double pSumG = 0.00;
	map<int, double>::iterator it;
	for (it = guv_.begin(); it != guv_.end(); ++it) {
		pSumG = pSumG + it->second;
	}
	pSumG = pSumG * doublePrice;

	maxDeltaRevenue = 0;
	double deltaRevenue;
	while (deltaPrice <= maxPriceChange_) {

		deltaRevenue = -pf * deltaPrice * deltaPrice + deltaPrice * pSumG * (1
				- influence_ * (1 + deltaPrice));

		deltaRevenue = deltaRevenue + -(influence_*deltaPrice*revenueGOfNeighbours(nodeIdToNodePtrIndex));

//		cout << "NodeId = " << nodeId_ << ": change in revenue = "
//				<< deltaRevenue << " : delta = " << deltaPrice<< endl;
		if (deltaRevenue > maxDeltaRevenue + EPSILON) {
			maxDeltaRevenue = deltaRevenue;
			bestDeltaPrice = deltaPrice;
		}
		deltaPrice = deltaPrice + 0.01;
	}

//	cout << "BEST: NodeId = " << nodeId_ << ": change in revenue = "
//					<< maxDeltaRevenue << " : delta = " << bestDeltaPrice<< endl;
//			cout << "---------------------------------------" <<endl ;

}

void Node::influentialEdgeRevenue(Node* n2, double& bestDelta,
		double& bestDelta2, double& bestMaxRevenue, Node** nodeIdToNodePtrIndex) {

	double pu = (price_);
	double iu = influence_;
	double deltaU = minPriceChange_;
	double pfu = pu * f_;
	double deltafu = 0.00;
	double gu1 = 0.00;
	double gu2 = 0.00;

	double pv = (n2->price());
	double iv = n2->influence();
	double deltaV = minPriceChange_;
	double pfv = pv * n2->f();
	double deltafv = 0.00;
	double gv1 = 0.00;
	double gv2 = 0.00;

	map<int, double>::iterator it;

	double guv = guv_[n2->nodeId()];

	bestMaxRevenue = 0.000;
	while (deltaU <= maxPriceChange_) {
		deltafu = -pfu * deltaU * deltaU;

		gu1 = 0.00;
		for (it = guv_.begin(); it != guv_.end(); ++it) {
			if (it->first != n2->nodeId())
				gu1 += it->second;
		}
		gu1 = gu1 * pu * deltaU * (1 - iu * (1 + deltaU));

		deltaV = minPriceChange_ ;
		while (deltaV <= maxPriceChange_) {
//			cout << deltaU << ":" << deltaV << endl ;
			deltafv = -pfv * deltaV * deltaV;

			//			double iuiv = -(iu*deltaU + iv*deltaV);

			// New strategy for scaling the iu and iv
			double iuiv = -(iu * deltaU + iv * deltaV) / 2.000;

			gu2 = pu * guv * (deltaU + (1 + deltaU) * iuiv);
			gv2 = pv * guv * (deltaV + (1 + deltaV) * iuiv);

			gv1 = 0.00;
			map<int, double> guvMap = n2->guv();
			for (it = guvMap.begin(); it != guvMap.end(); ++it) {
				if (it->first != nodeId_)
					gv1 += it->second;
			}
			gv1 = gv1 * pv * deltaV * (1 - iv * (1 + deltaV));

			double deltaRev = (deltafu + gu1 + gu2) + (deltafv + gv1 + gv2);

			deltaRev = deltaRev + -(iu*deltaU*revenueGOfNeighboursExceptV(nodeIdToNodePtrIndex, n2->nodeId()));
			deltaRev = deltaRev + -(iv*deltaV*n2->revenueGOfNeighboursExceptV(nodeIdToNodePtrIndex, nodeId_));

			cout << deltaU << ":" << deltaV << " Delta revenue " << deltaRev << endl ;
			if (deltaRev > bestMaxRevenue + EPSILON) {
				bestMaxRevenue = deltaRev;
				bestDelta = deltaU;
				bestDelta2 = deltaV;
			}
			deltaV = deltaV + 0.01;
		}
		deltaU = deltaU + 0.01;
	}

}

